/*	
	This program is free software; you can redistribute it and/or modify 
	it under the terms of the GNU General Public License as published by 
	the Free Software Foundation; either version 2 of the License, or 
	any later version.

    	This program is distributed in the hope that it will be useful, but 
	WITHOUT ANY WARRANTY; without even the implied warranty of 
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
	General Public License for more details.

    	You should have received a copy of the GNU General Public License 
	along with this program; if not, write to the Free Software 
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
	USA
*/

#include<interrupt.h>
#include<stdio.h>
#include<driver.h>
typedef struct descrittore interrupt_v;
interrupt_v IDT[IDT_DIM];

void handler_default(void) {asm("iret");}

void load_idt(interrupt_v * base_addr,int num_desc) {
	unsigned int idt[2];
	idt[0]=(num_desc*8)<<16;
	idt[1]=(unsigned int)base_addr;
	asm("": : :"memory");
	__asm__ __volatile__ ("lidt (%0)": :"g" ((char *)idt+2));
}

void add_idt(void (*handler)(void),int i,unsigned short opz) {
	if(i<IDT_DIM) {
		IDT[i].offset0_15=(unsigned int)handler & 0xFFFF;
		IDT[i].offset16_31=(unsigned int)handler >> 16;
		IDT[i].segmento = 0x8;
		IDT[i].opzioni = opz;
	} else {
		printk("Interrupt non valido");
	}
}

void init_IDT(void) {
	int i,j;
	long flags;
	save_eflag(flags);
	asm("cli");
	for(i=17;i<IDT_DIM;i++) {add_idt(handler_default,i,0x470);}
	//eccezioni
	add_idt(trap0,0,0x470);
	add_idt(trap1,1,0x470);
	add_idt(trap2,2,0x470);
	add_idt(trap3,3,0x470);
	add_idt(trap4,4,0x470);
	add_idt(trap5,5,0x470);
	add_idt(trap6,6,0x470);
	add_idt(trap7,7,0x470);
	add_idt(trap8,8,0x470);
	add_idt(trap9,9,0x470);
	add_idt(trap10,10,0x470);
	add_idt(trap11,11,0x470);
	add_idt(trap12,12,0x470);
	add_idt(trap13,13,0x470);
	add_idt(trap14,14,0x470);
	add_idt(trap15,15,0x470);
	add_idt(trap16,16,0x470);
	//irq
	add_irq(0,timer);
	add_irq(1,input_tastiera);
	add_irq(4,recv_serial);

	for(i=32;i<48;i++) {add_idt(handler_function,i,0x470);}
	load_idt(IDT,IDT_DIM);
	restore_eflag(flags);
}

void trap0(void) {printk("###Eccezione num1: Division by zero"); asm("hlt");}
void trap1(void) {printk("###Eccezione num2: NMI"); asm("hlt");}
void trap2(void) {printk("###Eccezione num3: Breakpoint"); asm("hlt");}
void trap3(void) {printk("###Eccezione num4: Overflow"); asm("hlt");}
void trap4(void) {printk("###Eccezione num5: Bound Range Exception"); asm("hlt");}
void trap5(void) {printk("###Eccezione num6: Invalid Opcode"); asm("hlt");}
void trap6(void) {printk("###Eccezione num7: Coprocessor Not Avaible"); asm("hlt");}
void trap7(void) {printk("###Eccezione num8: Double Fault"); asm("hlt");}
void trap8(void) {printk("###Eccezione num9: Coprocessor Segment Overrun"); asm("hlt");}
void trap9(void) {printk("###Eccezione num10: Invalid Task State Segment"); asm("hlt");}
void trap10(void) {printk("###Eccezione num11: Segment Not Present"); asm("hlt");}
void trap11(void) {printk("###Eccezione num12: Stack Fault"); asm("hlt");}
void trap12(void) {printk("###Eccezione num13: General Protection"); asm("hlt");}
void trap13(void) {printk("###Eccezione num14: Page Fault"); asm("hlt");}
void trap14(void) {printk("###Eccezione num15: SCONOSCIUTO"); asm("hlt");}
void trap15(void) {printk("###Eccezione num16: Error of Floating Point"); asm("hlt");}
void trap16(void) {printk("###Eccezione num17: Memory Not Alligned"); asm("hlt");}

void handler_function() {
	asm volatile(".globl handler_function \n"
		"handler_function: \n"
		"cli \n"
		"pusha \n"
		"pushl %ds \n"
		"pushl %es \n"
		"pushl %fs \n"
		"pushl %gs \n"
		"movl %esp,%eax \n"
		"pushl %eax \n"
		"call gestisci_irq \n"
		"popl %eax \n"
		"popl %gs \n"
		"popl %fs \n"
		"popl %es \n"
		"popl %ds \n"
		"popa \n"
		"sti \n"
		"iret \n"
	);
}
